﻿using System.Net;
using System.Threading.Tasks;

namespace Sidvall.Net
{
    public class HttpResponse
    {
        #region Public Members

        public IHttpContent Content { get; set; }
        #region IsSuccessStatusCode

        public bool IsSuccessStatusCode
        {
            get
            {
                if (((int)this.StatusCode >= 200) && ((int)this.StatusCode <= 299))
                    return true;
                return false;
            }
        }

        #endregion
        public HttpResponseHeaders Headers { get; set; }
        public string ReasonPhrase { get; set; }
        public HttpStatusCode StatusCode { get; set; }

        #region CopyContentToAsync

        public async Task CopyContentToAsync(System.IO.Stream stream)
        {
            await this.Content.CopyToAsync(stream).ConfigureAwait(false);
        }

        #endregion
        #region EnsureSuccessStatusCode

        public void EnsureSuccessStatusCode()
        {
            EnsureSuccessStatusCode(this.StatusCode, this.ReasonPhrase, !this.IsSuccessStatusCode, null);
        }
        public void EnsureSuccessStatusCode(string content)
        {
            EnsureSuccessStatusCode(this.StatusCode, this.ReasonPhrase, !this.IsSuccessStatusCode, content);
        }
        public static void EnsureSuccessStatusCode(HttpStatusCode statusCode, string message, bool isHttpError)
        {
            EnsureSuccessStatusCode(statusCode, message, isHttpError, null);
        }
        public static void EnsureSuccessStatusCode(HttpStatusCode statusCode, string message, bool isHttpError, string content)
        {
            if (statusCode == HttpStatusCode.Unauthorized)
            {
                var unauthorizedExceptionContext = Sidvall.Security.UnauthorizedExceptionContext.Deserialize(content);
                if (unauthorizedExceptionContext != null)
                    throw new Sidvall.Security.UnauthorizedException(unauthorizedExceptionContext);
                else
                    throw new Sidvall.Security.UnauthorizedException();
            }
            if (isHttpError)
            {
                if ((!string.IsNullOrWhiteSpace(content)) && (!string.IsNullOrWhiteSpace(message)))
                {
                    switch (message)
                    {
                        case Sidvall.Net.ReasonPhrases.BusinessExceptionReasonPhrase:
                            var businessExceptionContext = Sidvall.Business.BusinessExceptionContext.Deserialize(content);
                            if (businessExceptionContext != null)
                                throw new Sidvall.Business.BusinessException(businessExceptionContext);
                            else
                                throw new Sidvall.Business.BusinessException();
                        case Sidvall.Net.ReasonPhrases.UnauthenticatedExceptionReasonPhrase:
                            var unauthenticatedExceptionContext = Sidvall.Security.UnauthenticatedExceptionContext.Deserialize(content);
                            if (unauthenticatedExceptionContext != null)
                                throw new Sidvall.Security.UnauthenticatedException(unauthenticatedExceptionContext);
                            else
                                throw new Sidvall.Security.UnauthenticatedException();
                        default:
                            break;
                    }
                }
                throw new Sidvall.Net.HttpException(message, statusCode);
            }
        }

        #endregion
        #region EnsureSuccessStatusCodeAsync

        public async Task EnsureSuccessStatusCodeAsync()
        {
            if (this.StatusCode == HttpStatusCode.Unauthorized)
            {
                EnsureSuccessStatusCode();
            }
            else if (!this.IsSuccessStatusCode)
            {
                if (!string.IsNullOrWhiteSpace(this.ReasonPhrase))
                {
                    var content = await GetContentAsStringAsync().ConfigureAwait(false);
                    EnsureSuccessStatusCode(this.StatusCode, this.ReasonPhrase, !this.IsSuccessStatusCode, content);
                }
                else
                {
                    EnsureSuccessStatusCode();
                }
            }
        }

        #endregion
        #region GetContentAsByteArrayAsync

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public async Task<byte[]> GetContentAsByteArrayAsync()
        {
            return await this.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        }

        #endregion
        #region GetContentAsStreamAsync

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public async Task<System.IO.Stream> GetContentAsStreamAsync()
        {
            return await this.Content.ReadAsStreamAsync().ConfigureAwait(false);
        }

        #endregion
        #region GetContentAsStringAsync

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public async Task<string> GetContentAsStringAsync()
        {
            return await this.Content.ReadAsStringAsync().ConfigureAwait(false);
        }

        #endregion
        #region GetContentResolvedAsync

        public async Task<T> GetContentResolvedAsync<T>()
        {
            return await GetContentResolvedAsync<T>(true).ConfigureAwait(false);
        }
        public async Task<T> GetContentResolvedAsync<T>(bool requireSuccessStatusCode)
        {
            if (this.StatusCode == HttpStatusCode.NoContent)
                return default(T);
            var content = await GetContentAsStringAsync().ConfigureAwait(false);
            if (requireSuccessStatusCode)
                EnsureSuccessStatusCode(content);
            return Sidvall.Serialization.SerializerManager.Current.Deserialize<T>(content);
        }

        #endregion

        #endregion
        #region Constructors

        public HttpResponse()
        {
        }

        #endregion
    }
}
